import {ConfigEnv, Plugin, TransformResult, UserConfig, ViteDevServer} from 'vite';
import Utils from "../utils";
import {NodePath} from "@babel/traverse";
import {CallExpression} from "babel-types";
import {FileListen} from "../utils/FileListen";

export default function vitePluginDynamicImport(excludes: string[] = []): Plugin {
  let extensions: string[] = []
  let alias = {}
  let server: ViteDevServer
  return {
    name: "vite:vite-plugin-dynamic-import",
    config(config: UserConfig, env: ConfigEnv): UserConfig | void | Promise<UserConfig | void | null> | null {
      extensions = config.resolve.extensions;
      // 获取别名路径
      alias = Utils.getAliasPath(config)
      return config;
    },
    configureServer(_server) {
      server = _server
    },
    transform(code: string, id: string): Promise<TransformResult> | TransformResult {
      let map = null
      if (id.includes('node_modules') || excludes.some(item => id.includes(item))) {
        return {code, map}
      }
      if (/.js$|.jsx$|.ts$|.tsx$|.vue$/.test(id)) {
        const ast = Utils.getJsAst(code)
        const s = Utils.getMagicString(code)
        Utils.jsAstTraverse(ast, {
          CallExpression(ipath: NodePath<CallExpression>) {
            const node = ipath.node;
            const callee = node.callee;
            // @ts-ignore
            if (callee?.type === 'Import') {
              const arg0 = node.arguments[0]
              const pathNotVar = Utils.pathNotVar(arg0);
              if (pathNotVar.notVar) {
                if (pathNotVar.type !== 'StringLiteral') {
                  s.overwrite(node.start, node.end, `import('${pathNotVar.value}')`)
                }
              } else {
                let basePath = ''
                let oldBasePath = ''
                let endPath = ''
                if (arg0.type === 'TemplateLiteral') {
                  oldBasePath = basePath = arg0.quasis[0].value.raw
                  endPath = arg0.quasis[arg0.quasis.length - 1].value.raw
                } else if (arg0.type === 'BinaryExpression') {
                  oldBasePath = basePath = Utils.binaryExpressionGeBesttLeft(arg0)
                  endPath = Utils.binaryExpressionGeBesttRight(arg0)
                }
                basePath = Utils.getBasePath(alias, id, basePath)
                FileListen.viteAddDirListen(basePath, id, server)
                if (!oldBasePath.endsWith('/')) {
                  oldBasePath = oldBasePath + '/'
                }
                const files = Utils.readDirectory(basePath, true, new RegExp(endPath));
                let all = ''
                Object.keys(files).forEach(key => {
                  all += `'${key.replace('./', oldBasePath)}': ()=>import('${files[key]}'),`
                })
                const arg0Str = s.slice(arg0.start, arg0.end)
                let changeValue = Utils.transCodePathFiles(all, extensions, arg0Str, Utils.nodeAddFenge(ipath.parent))
                s.overwrite(node.start, node.end, changeValue + '()')
              }
            }
          },
        })
        map = Utils.getsouceMap(s, code)
        code = s.toString()
      }
      return {
        code,
        map
      };
    }
  }
}

// import(`@/views/dynamic-form/index.vue`), ===> import('@/views/dynamic-form/index.vue'), 不然识别为变量
